package Algorthim;

import searchTree.searchTreeNode;

import java.util.ArrayList;
import java.util.Vector;
import java.util.concurrent.locks.ReentrantLock;

public class HeavyWeight extends Algorithim implements Runnable {
	private Boolean first = true;
	private searchTreeNode node;
	private ReentrantLock splitLock;
	private volatile Splits numberOFSplits;
	private Vector<Thread> threads;

	public HeavyWeight(searchTreeNode node,Boolean firstCreated,ReentrantLock lock,Splits split,Vector<Thread> threads)
	{
		this.first = firstCreated;
		this.node = node;
		this.splitLock = lock;
		this.numberOFSplits = split;
		this.threads = threads;
	}
	
	@Override
	protected void handlePhaseOneReturn(searchTreeNode node, Integer firstleaf,
			Integer JunctionOne, Integer secoundleaf,
			Integer JunctionTwo, Integer thirdleaf, Integer forthleaf) 
	{

			splitLock.lock();
			if(numberOFSplits.getLimit() > 0)
			{
				searchTreeNode optionOne = cloner.deepClone(node);
				optionOne.cutBranch(globaldata.getPathMap(),firstleaf, JunctionOne);
				HeavyWeight newRunable = new HeavyWeight(optionOne, false, this.splitLock, numberOFSplits, threads);
				newRunable.setGlobalData(globaldata);
				threads.add(new Thread(newRunable));
				threads.get(threads.size() - 1).start();
				numberOFSplits.decLimit();

			}
			else
			{
				splitLock.unlock();
				searchTreeNode optionOne = cloner.deepClone(node);
				optionOne.cutBranch(globaldata.getPathMap(),firstleaf, JunctionOne);
				phaseOne(optionOne);

				searchTreeNode optionTwo = cloner.deepClone(node);
				optionTwo.cutBranch(globaldata.getPathMap(),secoundleaf, JunctionOne);
				phaseOne(optionTwo);

				searchTreeNode optionThree = cloner.deepClone(node);
				optionThree.cutBranch(globaldata.getPathMap(),thirdleaf, JunctionTwo);
				phaseOne(optionThree);

				searchTreeNode optionFour = cloner.deepClone(node);
				optionFour.cutBranch(globaldata.getPathMap(),forthleaf, JunctionTwo);
				phaseOne(optionFour);
				return;
			}
			
			if(numberOFSplits.getLimit() > 0)
			{
				searchTreeNode optionTwo = cloner.deepClone(node);
				optionTwo.cutBranch(globaldata.getPathMap(),secoundleaf, JunctionOne);
				HeavyWeight newRunable = new HeavyWeight(optionTwo, false, this.splitLock, numberOFSplits, threads);
				newRunable.setGlobalData(globaldata);
				threads.add(new Thread(newRunable));
				threads.get(threads.size() - 1).start();
				numberOFSplits.decLimit();

			}
			else
			{
				splitLock.unlock();
				searchTreeNode optionTwo = cloner.deepClone(node);
				optionTwo.cutBranch(globaldata.getPathMap(),secoundleaf, JunctionOne);
				phaseOne(optionTwo);

				searchTreeNode optionThree = cloner.deepClone(node);
				optionThree.cutBranch(globaldata.getPathMap(),thirdleaf, JunctionTwo);
				phaseOne(optionThree);

				searchTreeNode optionFour = cloner.deepClone(node);
				optionFour.cutBranch(globaldata.getPathMap(),forthleaf, JunctionTwo);
				phaseOne(optionFour);
				return;
			}
			
			if(numberOFSplits.getLimit() > 0)
			{
				searchTreeNode optionThree = cloner.deepClone(node);
				optionThree.cutBranch(globaldata.getPathMap(),thirdleaf, JunctionTwo);
				HeavyWeight newRunable = new HeavyWeight(optionThree, false, this.splitLock, numberOFSplits, threads);
				newRunable.setGlobalData(globaldata);
				threads.add(new Thread(newRunable));
				threads.get(threads.size() - 1).start();
				numberOFSplits.decLimit();

			}
			else
			{
				splitLock.unlock();
				searchTreeNode optionThree = cloner.deepClone(node);
				optionThree.cutBranch(globaldata.getPathMap(),thirdleaf, JunctionTwo);
				phaseOne(optionThree);

				searchTreeNode optionFour = cloner.deepClone(node);
				optionFour.cutBranch(globaldata.getPathMap(),forthleaf, JunctionTwo);
				phaseOne(optionFour);
				return;
			}

			splitLock.unlock();
			searchTreeNode optionFour = cloner.deepClone(node);
			optionFour.cutBranch(globaldata.getPathMap(),forthleaf, JunctionTwo);
			phaseOne(optionFour);
			
			if(first)
			{
				for(int i = 0 ; i < threads.size();i++)
				{
					Thread running = threads.get(i);
					if(running.isAlive())
					{
						try {
							running.join();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}
			return;
	}

	@Override
	protected void handlePhaseOneComplete(searchTreeNode node) {
		// currently not splitting the last phase as time involved should be very low
		this.createTranslation(node);
		this.phaseTwo(node);
	}

	@Override
	protected void handlePhaseTwoReturn(searchTreeNode node, Integer[] edgeOne,
			Integer[] edgeTwo) {
		searchTreeNode nodeOne = cloner.deepClone(node);
		searchTreeNode nodeTwo = node;

		nodeOne.getTree().removeEdge(edgeOne[0], edgeOne[1]); 
		nodeTwo.getTree().removeEdge(edgeTwo[0], edgeTwo[1]);

		phaseTwo(nodeOne);
		phaseTwo(nodeTwo);
	}

	@Override
	public void run() {
		phaseOne(this.node);
		try
		{
			splitLock.lock();
			numberOFSplits.incLimit();
		}
		finally
		{
			splitLock.unlock();
		}
	}

}
